# -*- coding: utf-8 -*-
# __author__ : "初一丶"
# __time__ : 2018/8/13 14:24
# __file__ : use_redis.py

import redis

"""
    连接redis 的方式: StrictRedis 和 Redis
        1.StrictRedis 用于实现大部分官方的命令, 并使用官方的语法和命令
        2.Redis是StrictRedis的子类,用于向前兼容redis-py.
    
     redis连接实例时线程安全的,所以可以直接设置为全局变量。直接使用 。
"""

# 严格的连接redis方式
# r = redis.StrictRedis(host='localhost', port=6379)

# 跟Python化的连接方式
# r = redis.Redis(host='localhost', port=6379)

"""
    Redis 连接池
        redis-py 使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。
        当并发量比较高的时候, 频繁的连接创建和释放对性能会有较高的影响
        默认情况下每个redis实例都会维护一个自己的连接池。
        可以直接建立一个连接池,然后调用Redis的作为参数。 这样就可以实现多个redis实例共享一个连接池
"""
pool = redis.ConnectionPool(host='localhost', port=6379, max_connections=10)
r = redis.Redis(connection_pool=pool)


# ===========  Redis 操作 ===============
# set(name, value, ex=None, px=None, nx=False, xx=False)
# ex:过期时间(秒)， px:过期时间(毫秒)， nx:设置为True时,只有当key(name)不存在set才执行. xx:为True时,只有当key存在时才执行(更新操作)
r.set('name', 'tom')
r.get('name').decode()                      # get得到的是字节类型,需要结果为字符串时需要用decode()


# setnx(name, value)  设置值, 只有name不存在时,执行设置操作
r.setnx('name', 'Lily')                     # 因为name上面已经设置为tome 所以setnx并不会执行 返回False

# setex(name, value, time) 、psetex(name, time_ms, value)  time:过期时间(秒 或 timedelta对象), time_ms:毫秒
r.setex('age', '16', 100)

# mset(*args, **kwargs) 批量设置值
r.mset({'cc': 123, 'dd': 34})               # 可以是字典
r.mset(aa=1, bb=99)                         # key不带引号,不然会报错
print(r.get('bb').decode())

# mget(keys, *args) 批量获取值
print(r.mget(['aa', 'bb', 'cc', 'dd']))     # 输出: [b'1', b'99', b'123', b'34']

# getset(name, value) 设置新值 并获取原来的值
r.set('address', 'BeiJing')
print(r.getset('address', 'ShangHai'))      # b'BeiJing'
print(r.get('address'))                     # b'ShangHai'

# strlen(name) 返回name对应值的字节长度(一个汉字3个字节)
r.strlen('cc')

# incr(self, name, amount=1) 自增name对应的值,当name不存在时自动创建name=amount。否则，则自增。当value非数字时，报错
r.incr('age', amount=1)

# incrbyfloat(self, name, amount=1.0) 同incr value必须是浮点型
r.incrbyfloat('price', amount=1.2)

# decr(self, name, amount=1) 自减name对应的值,不存在时 则自动创建name=amount. value必须为整数
r.decr('year', amount=2)

# append(ket, value) 在name对应的值后面追加内容,如果值为非字符串 会被自动转换成字符串
r.set('python', 'hello')
r.append('python', ' world')
print(r.get('python'))                      # b'hello world'


"""
    List 操作
        redis中的list在内存中按照一个name对应一个list来存储
        注意: list类型用get不行，需要用lrange(name, 0, -1)来取全部的值
"""

# lpush(name, values) 在name对应的list中添加元素,只有name已经存在时，值添加到列表的最左边  rpush表示从右向左操作
r.lpush('list', 11, 22, 33, 44)
print(r.lrange('list', 0, -1))              # [b'44', b'33', b'22', b'11']

# lpushx(name, value) 在name对应的list中添加元素,如果name已经存在.值添加到列表的最左边   rpushx(name, value) 添加到右边
r.lpushx('list', 1)
print(r.lrange('list', 0, -1))              # [b'1', b'44', b'33', b'22', b'11']

# llen(name) name对应的list元素个数
r.llen('list')

# linsert(name, where, refvalue, value) 在name 对应的列表的某一个值前或者后 插入一个新值
r.linsert('list', where='before', refvalue=22, value=56)
print(r.llen('list'))                       # 6
print(r.lrange('list', 0, -1))              # [b'1', b'44', b'33', b'56', b'22', b'11']

# lset(name, index, value) 对name对应的list中的某一个索引位置重新赋值
r.lset('list', 1, 66)
print(r.lrange('list', 0, -1))              # [b'1', b'66', b'33', b'56', b'22', b'11']

# lrem(name, value, num) 在name对应的list中删除指定的值，以及后面的几个元素
# 有多个相同值时  name = 0: 删除列表中所有的值  name = 2: 从前到后,删除两个    name = -2 ：从后到前 删除两个
r.lrem('list', 66, num=1)
print(r.lrange('list', 0, -1))              # [b'1', b'33', b'56', b'22', b'11']

# lpop(name) name对应的列表从左边数获取第一个元素 并从中剔除. rpop(name) 从右边弹出
print(r.lpop('list'))                       # b'1'
print(r.lrange('list', 0, -1))              # [b'33', b'56', b'22', b'11']

# lindex(name, index) 在name对应的列表中根据索引获取元素


"""
 更多操作Redis的API 请结合源码和附件(redis笔记.doc) 自行测试
"""

